home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 42
/
Amiga Format AFCD42 (Issue 126, Aug 1999).iso
/
-serious-
/
comms
/
other
/
slrn
/
slrn_src
/
src
/
grplens.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-05-14
|
24KB
|
1,253 lines
/* -*- mode: C; mode: fold -*- */
/* Copyright (c) 1998 John E. Davis (davis@space.mit.edu)
*
* This file is part of slrn.
*
* Slrn is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* Slrn is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with Slrn; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "slrnfeat.h"
#include <stdio.h>
#include <string.h>
#if SLRN_HAS_GROUPLENS
/* Rest of file in this #if statement */
#include <slang.h>
#include <stdarg.h>
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#include <ctype.h>
#include "jdmacros.h"
#include "slrn.h"
#include "group.h"
#include "art.h"
#include "misc.h"
#include "uudecode.h"
#include "grplens.h"
#include "sltcp.h"
#include "util.h"
#include "server.h"
#define GL_MAX_RESPONSE_LINE_LEN 1024
/*{{{ GL_Type structure */
typedef struct GL_Type /*{{{*/
{
char *hostname;
int port;
char *token;
char *pseudoname;
int logged_in;
SLTCP_Type *tcp;
struct GL_Type *next;
}
/*}}}*/
GL_Type;
static GL_Type GL_Nameserver;
static GL_Type *GL_Server_List;
/*}}}*/
typedef struct /*{{{*/
{
char *msgid;
float pred;
float confhigh;
float conflow;
}
/*}}}*/
GL_Prediction_Type;
typedef struct /*{{{*/
{
char *msgid;
int rating;
int saw_article;
}
/*}}}*/
GL_Rating_Type;
char *Slrn_GroupLens_Host;
int Slrn_GroupLens_Port;
char *Slrn_GroupLens_Pseudoname;
typedef struct GL_Newsgroup_List_Type /*{{{*/
{
char *group;
GL_Type *gl;
struct GL_Newsgroup_List_Type *next;
}
/*}}}*/
GL_Newsgroup_List_Type;
static GL_Newsgroup_List_Type *Newsgroup_List = NULL;
/*{{{ Error codes and Error functions */
static int GL_Error;
#define GL_ERROR_UNKNOWN -1
#define GL_ELOGIN_UNREGISTERED 1
#define GL_ELOGIN_BUSY 2
#define GL_ELOGIN_UNAVAILABLE 3
#define GL_ELOGIN_ALREADY_LOGGEDIN 4
#define GL_ERROR_PROPER_RESPONSE 6
#define GL_ERROR_MALLOC 7
#define GL_ESERVER_WRITE 8
#define GL_ESERVER_READ 9
#define GL_ERROR_TOKEN 10
#define GL_ERROR_NEWSGROUP 11
typedef struct /*{{{*/
{
char *err;
unsigned int len;
int errcode;
}
/*}}}*/
GL_Error_Type;
/*{{{ Utility functions */
static char *make_nstring (char *s, unsigned int len) /*{{{*/
{
char *s1;
if (s == NULL) return s;
if (NULL == (s1 = (char *) malloc (len + 1)))
{
GL_Error = GL_ERROR_MALLOC;
return NULL;
}
strncpy (s1, s, len);
s1[len] = 0;
return s1;
}
/*}}}*/
static char *make_string (char *s) /*{{{*/
{
if (s == NULL) return s;
return make_nstring (s, strlen (s));
}
/*}}}*/
static char *skip_whitespace (char *s) /*{{{*/
{
char ch;
while (((ch = *s) != 0) && isspace(ch)) s++;
return s;
}
/*}}}*/
static char *skip_nonwhitespace (char *s) /*{{{*/
{
char ch;
while (((ch = *s) != 0) && (0 == isspace(ch))) s++;
return s;
}
/*}}}*/
/*}}}*/
static char *gl_get_error (void) /*{{{*/
{
switch (GL_Error)
{
case GL_ELOGIN_UNREGISTERED: return "User is Unregistered";
case GL_ELOGIN_BUSY: return "Service is Busy";
case GL_ELOGIN_UNAVAILABLE: return "Service Unavailable";
case GL_ELOGIN_ALREADY_LOGGEDIN: return "Already logged in";
case GL_ERROR_PROPER_RESPONSE: return "Server failed to return proper response";
case GL_ERROR_MALLOC: return "Not enough memory";
case GL_ESERVER_WRITE: return "Error writing to server";
case GL_ESERVER_READ: return "Error reading from server";
case GL_ERROR_TOKEN: return "Token is invalid";
case GL_ERROR_NEWSGROUP: return "Newsgroup not supported";
}
return "Unknown Error";
}
/*}}}*/
static void close_gl (GL_Type *gl) /*{{{*/
{
if (gl == NULL) return;
sltcp_close (gl->tcp);
gl->tcp = NULL;
}
/*}}}*/
static int get_gl_response (GL_Type *gl, char *buf, unsigned int len) /*{{{*/
{
char *b;
(void) len;
if (-1 == sltcp_fgets (gl->tcp, buf, GL_MAX_RESPONSE_LINE_LEN))
{
GL_Error = GL_ESERVER_READ;
close_gl (gl);
return -1;
}
b = buf + strlen (buf);
if (b != buf)
{
b--;
if (*b == '\n') *b = 0;
if (b != buf)
{
b--;
if (*b == '\r') *b = 0;
}
}
return 0;
}
/*}}}*/
static void handle_error_response (GL_Type *gl, GL_Error_Type *tbl) /*{{{*/
{
char *s, *s1;
char buf [GL_MAX_RESPONSE_LINE_LEN];
if (-1 == get_gl_response (gl, buf, sizeof (buf)))
return;
if (tbl == NULL)
return;
s = skip_whitespace (buf);
GL_Error = GL_ERROR_UNKNOWN;
while (*s != 0)
{
unsigned int len;
GL_Error_Type *t;
s1 = skip_nonwhitespace (s);
len = s1 - s;
t = tbl;
while (t->err != NULL)
{
if ((t->len == len)
&& (0 == slrn_case_strncmp ((unsigned char *)s, (unsigned char *) t->err, len)))
{
GL_Error = t->errcode;
if (GL_Error == GL_ERROR_TOKEN)
{
if (gl->token != NULL)
free (gl->token);
gl->token = NULL;
gl->logged_in = 0;
}
break;
}
t++;
}
s = skip_whitespace (s1);
}
close_gl (gl);
}
/*}}}*/
static int is_error (char *buf) /*{{{*/
{
if (!slrn_case_strncmp ((unsigned char *) buf, (unsigned char *) "ERROR", 5))
return 1;
return 0;
}
/*}}}*/
/*}}}*/
/*{{{ parse_keyword_eqs_value */
/* Scan buf looking for keyword=VALUE */
static int parse_keyword_eqs_value (char *buf, char *kw, char **value, unsigned int *len) /*{{{*/
{
char *b, *b1, *v, *v1;
char ch;
unsigned int kwlen;
*value = NULL;
kwlen = strlen (kw);
b = buf;
while (1)
{
b = skip_whitespace (b);
if (*b == 0) return -1;
b1 = b;
while (((ch = *b1) != 0) && (0 == isspace (ch)) && (ch != '='))
b1++;
if (ch == 0) return -1;
if (ch != '=')
{
b = b1;
continue;
}
v = b1 + 1;
if (*v == '"')
{
v++;
v1 = v;
while (((ch = *v1) != 0) && (ch != '"')) v1++;
}
else v1 = skip_nonwhitespace (v);
if ((b + kwlen == b1)
&& (0 == slrn_case_strncmp ((unsigned char *) kw, (unsigned char *) b, kwlen)))
{
*value = v;
*len = v1 - v;
return 0;
}
if (*v1 == '"') v1++;
b = v1;
}
}
/*}}}*/
/*}}}*/
/*{{{ low level GL server functions */
static int send_gl_line (GL_Type *gl, char *msg, int flush) /*{{{*/
{
if (msg == NULL) return 0;
if ((-1 == sltcp_fputs (gl->tcp, msg))
|| (-1 == sltcp_fputs (gl->tcp, "\r\n"))
|| (flush && (-1 == sltcp_flush_output (gl->tcp))))
{
GL_Error = GL_ESERVER_WRITE;
close_gl (gl);
return -1;
}
return 0;
}
/*}}}*/
static int connect_to_gl_host (GL_Type *gl, char *cmd) /*{{{*/
{
char buf [GL_MAX_RESPONSE_LINE_LEN];
char *host;
int port;
GL_Error = 0;
port = gl->port;
if (NULL == (host = gl->hostname))
{
host = Slrn_GroupLens_Host;
port = Slrn_GroupLens_Port;
}
if ((host == NULL) || (port <= 0))
{
GL_Error = GL_ERROR_UNKNOWN;
return -1;
}
if (NULL == (gl->tcp = sltcp_open_connection (host, port)))
return -1;
/* We should be able to read OK ... If not, we failed to make proper
* connection.
*/
if (-1 == get_gl_response (gl, buf, sizeof (buf)))
return -1;
if (0 != slrn_case_strncmp ((unsigned char *) buf, (unsigned char *) "OK", 2))
{
GL_Error = GL_ERROR_PROPER_RESPONSE;
close_gl (gl);
return -1;
}
return send_gl_line (gl, cmd, 1);
}
/*}}}*/
static int start_command (GL_Type *gl, char *fmt, ...) /*{{{*/
{
va_list ap;
int ret;
if (-1 == connect_to_gl_host (gl, NULL))
return -1;
va_start(ap, fmt);
ret = sltcp_vfprintf (gl->tcp, f